# 打开网页
import os
import traceback
from pathlib import Path

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, StaleElementReferenceException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

from tools import *


# 指定 chromedriver 路径


def init_browser(driver_path):
    # 设置 Chrome 参数

    options = Options()

    options.page_load_strategy = 'eager'  # 只等待 DOMContentLoaded，不等页面完全加载

    options.add_argument("--disable-blink-features=AutomationControlled")  # 防检测

    options.add_argument('--disable-extensions')

    options.add_argument('--no-sandbox')

    options.add_argument('--disable-dev-shm-usage')

    options.add_argument('--disable-gpu')

    # # 禁止图片和css加载
    # prefs = {"profile.managed_default_content_settings.images": 2, 'permissions.default.stylesheet': 2}
    # options.add_experimental_option("prefs", prefs)
    # options.add_argument('--disable-images')  # 可配合 Chrome 插件或 DevTools 限制加载图片

    options.add_experimental_option("excludeSwitches", ["enable-logging"])  # 关闭警告

    options.add_experimental_option("excludeSwitches", ["enable-automation"])  # 防止出现“Chrome正在受到自动测试软件的控制”

    options.add_experimental_option("useAutomationExtension", False)  # 禁用扩展

    # 可选：无头模式（不显示浏览器）

    # 使用无头模式  过去验证码后得到的Cookie不能使用

    # options.add_argument("--headless")

    # 启动 driver

    service = Service(driver_path)

    driver = webdriver.Chrome(service=service, options=options)

    # 执行 JavaScript 删除 navigator.webdriver 特征值

    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {

        "source": """

                Object.defineProperty(navigator, 'webdriver', {

                    get: () => undefined

                });
            """

    })

    return driver


def set_cookie(driver, cookies):
    for cookie in cookies:

        selenium_cookie = {

            'name': cookie.name,

            'value': cookie.value,

            'domain': cookie.domain,  # 如果报错，可删掉这个字段试试

            'path': cookie.path,

        }

        try:

            driver.add_cookie(selenium_cookie)

        except Exception as e:

            print(f"添加 cookie 出错: {e}, cookie={selenium_cookie}")


def bypass_selenium(cookies, driver):
    time.sleep(1)

    # set_cookie(driver, cookies)

    # driver.get("https://www.smzdm.com/jingxuan/")

    try:

        driver.switch_to.frame(0)

        """

        JS方式
        """

        # 下载背景图

        p1 = download_slider_bg(driver, "#slideBg", OTHER_PATH + 'img1.png')

        # 下载滑块图

        p2 = download_slider_bg(driver, "#tcOperation > div:nth-child(7)", OTHER_PATH + "img2.png")

        # print(f"滑块应该移动到的位置 x = {x}")

        p2 = crop_and_save(p2, (130, 480), (270, 630), OTHER_PATH + "cropped.png")

        # TODO 获取时间  将图片保存为图片，便于判断滑块是否正确通过

        x = detect_displacement(p2, p1, save_path=OTHER_PATH + "marked_gap.png")

        if not x:

            print("未找到缺口位置")

        else:

            # 可模拟点击、拖动等操作

            res = drag_captcha_by_js(driver, x)

        time.sleep(0.5)

        driver.save_screenshot(OTHER_PATH + "full_page.png")  # 保存截图到当前目录

        if "崩溃啦" in driver.page_source:
            time.sleep(1)
            driver.refresh()
            time.sleep(1)

    except Exception as e:

        # print("发生异常:", e)

        traceback.print_exc("发生异常")

    finally:

        driver.switch_to.default_content()

        print("滑块模拟结束")

        time.sleep(4)

        print("新的cookie => ", driver.get_cookies())

        return driver.get_cookies()


def query(driver, ori_text, retry_count=0, pre_url=""):
    try:
        time.sleep(2)

        # 验证码检测
        if "2s后自动为您刷新验证码" in driver.page_source:
            print("出现验证码，品牌", ori_text)
            bypass_selenium({}, driver)
            if retry_count < 3:
                return query(driver, ori_text, retry_count + 1)
            else:
                print("重试次数过多，跳过")
                return None, driver.current_url

        # 搜索框
        search_input = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.CLASS_NAME, "search-input"))
        )

        # 查询按钮
        search_button = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.CLASS_NAME, "search-submit"))
        )
        search_input.click()
        search_input.clear()
        search_input.send_keys(ori_text)

        search_button.click()

        WebDriverWait(driver, 15).until(lambda d: d.current_url != pre_url)

        # 等待搜索结果
        first_brand_elem = WebDriverWait(driver, 5).until(
            EC.visibility_of_element_located((
                By.XPATH,
                '//*[@id="filter-block"]/div[.//text()[normalize-space(.)="品牌"]]/div[2]/div[2]/div/a[1]'
            ))
        ).text.strip()

        # # 停止页面加载（不会影响已加载的 DOM）
        # driver.execute_script("window.stop();")

        # 提取品牌
        return first_brand_elem, driver.current_url

    except TimeoutException:
        driver.refresh()
        return None, driver.current_url
    except StaleElementReferenceException:
        print("元素失效，重试获取...")
        driver.refresh()
        if retry_count < 3:
            return query(driver, ori_text, retry_count + 1)
        else:
            print("重试次数过多，跳过")
            return None, driver.current_url
    except Exception as e:
        print(f"位置2 查询“{ori_text}”时发生错误：{str(e)[:200]}")
        # traceback.print_exc()
        return None, driver.current_url


DRIVER = init_browser(Path.cwd() / DRIVER_PATH)

if __name__ == '__main__':

    # 从数据库读取 error 为 1 且 standard_name 为 Null 的记录

    table = "brand_mapping"
    # sql = f"-- SELECT original_name FROM {table} WHERE error = 1 AND standard_name IS NULL"
    sql = f"SELECT original_name FROM {table} WHERE error = 1"

    DRIVER.get("https://www.smzdm.com/")
    pre_url = ""
    while True:
        try:
            # 避免太频繁执行sql查询 很浪费性能
            time.sleep(1.5)
            cursor.execute(sql)

            data = cursor.fetchone()

            if not data: continue

            ori_brand = data[0]

            standard_brand, pre_url = query(DRIVER, ori_brand, pre_url=pre_url)

            # 将提取后的品牌信息推送至数据库

            if standard_brand:
                print("原品牌", ori_brand, "值得买对应品牌", standard_brand)
                lis = ["其它品牌", "其它", "其他家", "其他品牌", "其他", "未知", "", "无", 'others/其他']
                if ori_brand in lis or standard_brand in lis:
                    standard_brand = "未知品牌"

                cursor.execute(
                    f"UPDATE  {table} SET standard_name = %s,multiple_flag = %s,error = %s WHERE original_name = %s",
                    (standard_brand, 0, 0, ori_brand)
                )
                conn.commit()
            else:
                # 标记为  selenium 查询品牌也出错的状态 与2相或之后存入数据库记录
                cursor.execute(
                    f"UPDATE  {table} SET error = {3} WHERE original_name = %s",
                    (ori_brand)
                )
                print(f"未获取到品牌信息 => {ori_brand}, 已记录至数据库,并更新错误代码")

                conn.commit()
        except KeyboardInterrupt:
            os._exit(0)

        except Exception as e:
            print(f"位置1 查询{data}出错=>{str(e)[:200]}",)
            # traceback.print_exc()
            # DRIVER.refresh()
            continue
